package com.qinglei.recoup.common.authentication;

import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.tenant.TenantContextHolder;
import com.qinglei.recoup.common.utils.RecoupUtil;
import com.qinglei.recoup.common.utils.HttpContextUtil;
import com.qinglei.recoup.common.utils.IPUtil;
import com.qinglei.recoup.system.domain.Tenant;
import com.qinglei.recoup.system.domain.User;
import com.qinglei.recoup.system.manager.UserManager;
import com.qinglei.recoup.system.service.TenantService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;

/**
 * 自定义实现 ShiroRealm，包含认证和授权两大模块
 *
 * @author MrBird
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private RedisService redisService;
    @Autowired
    private UserManager userManager;
    @Resource
    private TenantService tenantService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    /**`
     * 授权模块，获取用户角色和权限
     *
     * @param token token
     * @return AuthorizationInfo 权限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) {
        Long userId = JWTUtil.getUserId(token.toString());

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        // 获取用户角色集
        Set<String> roleSet = userManager.getUserRoles(userId);
        simpleAuthorizationInfo.setRoles(roleSet);

        // 获取用户权限集
//        Set<String> permissionSet = userManager.getUserPermissions(userId);
//        simpleAuthorizationInfo.setStringPermissions(permissionSet);
        return simpleAuthorizationInfo;
    }

    /**
     * 用户认证
     *
     * @param authenticationToken 身份认证 token
     * @return AuthenticationInfo 身份认证信息
     * @throws AuthenticationException 认证相关异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 这里的 token是从 JWTFilter 的 executeLogin 方法传递过来的，已经经过了解密
        String token = (String) authenticationToken.getCredentials();

        // 从 redis里获取这个 token
        // HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
//        String ip = IPUtil.getIpAddr(request);

        String encryptTokenInRedis = null;
        try {
            encryptTokenInRedis = redisService.get(CommonConstant.TOKEN_CACHE_PREFIX + token);
        } catch (Exception ignore) {
        }
        // 如果找不到，说明已经失效
        if (StringUtils.isBlank(encryptTokenInRedis))
            throw new AuthenticationException("token已经过期");

        Long userId = JWTUtil.getUserId(token);

        if (userId == null) {
            throw new AuthenticationException("token校验不通过");
        }

        // 通过用户名查询用户信息
        User user = userManager.getUserById(userId);

        if (user == null) {
            throw new AuthenticationException("用户不存在");
        }
        if (!user.getStatus().equals(User.STATUS_VALID)) {
            throw new AuthenticationException("用户已禁用");
        }
        if (!JWTUtil.verify(token, userId, user.getPassword())) {
            throw new AuthenticationException("token校验不通过");
        }
        // 检查租户是否禁用
        if (user.getTenantId() != null && user.getTenantId() != 0) {
            Tenant tenant = tenantService.getById(user.getTenantId());
            if (tenant == null || !tenant.getStatus().equals(CommonConstant.STATUS_ENABLE)) {
                throw new AuthenticationException("机构不存在或已被禁用");
            }
        }
        // 设置租户ID
        if (user.getTenantId() != null && user.getTenantId() != 0) {
            TenantContextHolder.setTenantId(user.getTenantId());
        }
        return new SimpleAuthenticationInfo(token, token, "recoup_shiro_realm");
    }
}
